home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_200 / 236_01 / fcomp.c < prev    next >
Text File  |  1989-06-05  |  5KB  |  259 lines

  1. /*
  2.     HEADER:        CUG236;
  3.     TITLE:        Compare Text Files;
  4.     DATE:        05/17/1987;
  5.     DESCRIPTION:    "Best version of DIFF (file comparator) from Jan '86
  6.             issue of Software Practice and Experience.";
  7.     VERSION:    1.1;
  8.     KEYWORDS:    File Comparator, File Compare, File Comparison, File
  9.             Comparison Utility;
  10.     FILENAME:    FCOMP.C;
  11.     SEE-ALSO:    DIFF;
  12.     COMPILERS:    vanilla;
  13.     AUTHORS:    Chuck Allison;
  14.     WARNINGS:    When compiling under MSDOS, you need to increase the 
  15.             stack size and use the large model.
  16. */
  17.  
  18. /* fcomp.c:    file comparator that beats DIFF! */
  19.  
  20. #include <stdio.h>
  21.  
  22. /*
  23.  * Portability Note:  8-bit systems often don't have header file string.h.
  24.  * If your system doesn't have it, uncomment the following #define.
  25.  */
  26.  
  27. /*
  28. #define NO_STRING_H
  29. */
  30.  
  31. /*
  32.  * Portability Note:  Back in K & R days, standard library function malloc()
  33.  * was called alloc().    Some compilers (e.g. Eco-C under CP/M) haven't made
  34.  * the name change.  If yours is one of these compilers, uncomment the
  35.  * following #define:
  36.  */
  37.  
  38. /*
  39. #define malloc(p)    alloc(p)
  40. */
  41.  
  42. /*
  43.  * Portability Note:  The AZTEC C compilers handle the binary/text file
  44.  * dichotomy differently from most other compilers.  Uncomment the following
  45.  * pair of #defines if you are running AZTEC C:
  46.  */
  47.  
  48. /*
  49. #define getc(f)        agetc(f)
  50. #define putc(c,f)    aputc(c,f)
  51. */
  52.  
  53. #ifdef    NO_STRING_H
  54. int strcmp(), strlen();
  55. #else
  56. #include <string.h>
  57. #endif
  58.  
  59. #define MAXLINES 1000
  60. #define ORIGIN MAXLINES
  61. #define INSERT 1
  62. #define DELETE 2
  63.  
  64. struct edit {
  65.    struct edit *link;
  66.    int op;
  67.    int line1;
  68.    int line2;
  69. };
  70.  
  71. char *A[MAXLINES], *B[MAXLINES];
  72.  
  73. void exit();
  74.  
  75. void main(argc,argv)
  76. int argc;
  77. char *argv[];
  78. {
  79.    int     col, d, k, lower, m, max_d, n, row, upper;
  80.    int last_d[2*MAXLINES+1];
  81.    struct edit *new, *script[2*MAXLINES+1];
  82.    char *malloc();
  83.    int atoi(), in_file();
  84.    void exceed(), fatal(), put_scr();
  85.  
  86.    if (argc > 1 && argv[1][0] == '-')
  87.    {
  88.       max_d = atoi(&argv[1][1]);
  89.       ++argv;
  90.       --argc;
  91.    }
  92.    else
  93.       max_d = 2*MAXLINES;
  94.  
  95.    if(argc != 3)
  96.       fatal("fcomp requires two file names.");
  97.  
  98.    m = in_file(argv[1],A);
  99.    n = in_file(argv[2],B);
  100.  
  101.    for (row=0 ; row<m && row < n && strcmp(A[row],B[row]) == 0 ; ++row)
  102.       ;
  103.    last_d[ORIGIN] = row;
  104.    script[ORIGIN] = NULL;
  105.    lower = (row == m) ? ORIGIN + 1 : ORIGIN - 1;
  106.    upper = (row == n) ? ORIGIN - 1 : ORIGIN + 1;
  107.    if (lower > upper)
  108.    {
  109.       puts("The files are identical.");
  110.       exit(0);
  111.    }
  112.  
  113.    for (d = 1 ; d <= max_d ; ++d)
  114.    {
  115.       for ( k = lower ; k <= upper ; k +=2)
  116.       {
  117.      new = (struct edit *) malloc(sizeof(struct edit));
  118.      if (new == NULL)
  119.         exceed(d);
  120.  
  121.      if (k == ORIGIN-d || k != ORIGIN+d && last_d[k+1] >= last_d[k-1])
  122.      {
  123.         row = last_d[k+1]+1;
  124.         new->link = script[k+1];
  125.         new->op = DELETE;
  126.      }
  127.      else
  128.      {
  129.         row = last_d[k-1];
  130.         new->link = script[k-1];
  131.         new->op = INSERT;
  132.      }
  133.      new->line1 = row;
  134.      new->line2 = col = row + k - ORIGIN;
  135.      script[k] = new;
  136.  
  137.      while(row < m && col < n && strcmp(A[row],B[col]) == 0)
  138.      {
  139.         ++row;
  140.         ++col;
  141.      }
  142.      last_d[k] = row;
  143.  
  144.      if (row == m && col == n)
  145.      {
  146.         put_scr(script[k]);
  147.         exit(!0);
  148.      }
  149.      if (row == m)
  150.         lower = k+2;
  151.  
  152.      if (col == n)
  153.         upper = k-2;
  154.       }
  155.       --lower;
  156.       ++upper;
  157.    }
  158.    exceed(d);
  159. }
  160.  
  161. int in_file(filename,P)
  162. char *filename, *P[];
  163. {
  164.    char buf[100], *malloc(), *save, *b;
  165.    FILE *fp;
  166.    int lines = 0;
  167.    void fatal();
  168.  
  169.    if ((fp = fopen(filename,"r")) == NULL)
  170.    {
  171.       fprintf(stderr, "Cannot open file %s.\n",filename);
  172.       exit(!0);
  173.    }
  174.  
  175.    while(fgets(buf,100,fp) != NULL)
  176.    {
  177.       if (lines >= MAXLINES)
  178.      fatal("File is too large for diff.");
  179.       if ((save = malloc(strlen(buf)+1)) == NULL)
  180.      fatal("Not enough room to save the files.");
  181.       P[lines++] = save;
  182.       for (b = buf ; *save++ = *b++ ; )
  183.      ;
  184.    }
  185.    fclose(fp);
  186.    return(lines);
  187. }
  188.  
  189. void put_scr(start)
  190. struct edit *start;
  191. {
  192.    struct edit *ep, *behind, *ahead, *a, *b;
  193.    int change;
  194.  
  195.    ahead = start;
  196.    ep = NULL;
  197.    while (ahead != NULL)
  198.    {
  199.       behind = ep;
  200.       ep = ahead;
  201.       ahead = ahead->link;
  202.       ep->link = behind;
  203.    }
  204.  
  205.    while( ep != NULL)
  206.    {
  207.       b = ep;
  208.       if (ep->op == INSERT)
  209.      printf("Inserted after line %d:\n",ep->line1);
  210.       else
  211.       {
  212.      do
  213.      {
  214.         a = b;
  215.         b = b->link;
  216.      } while (b!=NULL && b->op == DELETE && b->line1 == a->line1+1);
  217.  
  218.      change = (b!=NULL && b->op == INSERT && b->line1 == a->line1);
  219.      if (change)
  220.         printf("\nChanged ");
  221.      else
  222.         printf("\nDeleted ");
  223.      if (a == ep)
  224.         printf("line %d\n",ep->line1);
  225.      else
  226.         printf("lines %d-%d:\n",ep->line1,a->line1);
  227.  
  228.      do
  229.      {
  230.         printf(" %s",A[ep->line1-1]);
  231.         ep = ep->link;
  232.      } while (ep != b);
  233.  
  234.      if (!change)
  235.         continue;
  236.      printf("To:\n");
  237.       }
  238.       do
  239.       {
  240.      printf(" %s",B[ep->line2-1]);
  241.      ep = ep->link;
  242.       } while (ep != NULL && ep->op == INSERT && ep->line1 == b->line1);
  243.    }
  244. }
  245.  
  246. void fatal(msg)
  247. char *msg;
  248. {
  249.    fprintf(stderr,"%s\n",msg);
  250.    exit(!0);
  251. }
  252.  
  253. void exceed(d)
  254. int d;
  255. {
  256.    fprintf(stderr,"The files differ in at least %d lines. \n",d);
  257.    exit(!0);
  258. }
  259.